#include <stdio.h>
#include <gst/gst.h>

static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data)
{
    GMainLoop *loop = (GMainLoop *) data;
    bus = bus;
    switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
        g_print ("End of stream\n");
        g_main_loop_quit (loop);
        break;
    case GST_MESSAGE_ERROR: {
        gchar *debug;
        GError *error;
        gst_message_parse_error (msg, &error, &debug);
        g_free (debug);
        g_printerr ("Error: %s\n", error->message);
        g_error_free (error);
        g_main_loop_quit (loop);
        break;
    }
    default:
        break;
    }
    return TRUE;
}

static void on_pad_added(GstElement *element, GstPad *pad, gpointer data)
{
    GstPad *sinkpad;
    GstElement *decoder = (GstElement *)data;
    element = element;

    g_message("%s[%d] Dynamic pad created, linking demuxer/decoder\n", __func__, __LINE__);

    sinkpad = gst_element_get_static_pad(decoder, "sink");
    gst_pad_link(pad, sinkpad);

    gst_object_unref(sinkpad);
}

int main(int argc, char *argv[])
{
    GMainLoop *loop = NULL;
    GstElement *pipeline = NULL;
    GstElement *source = NULL;
    GstElement *demuxer = NULL;
    GstElement *decoder = NULL;
    GstElement *conv = NULL;
    GstElement *sink = NULL;
    GstBus *bus = NULL;
    guint busWatchID;

    /* initialisation */
    gst_init(&argc, &argv);

    loop = g_main_loop_new(NULL, FALSE);

    /* Check input arguments */
    if (argc != 2) {
        g_printerr("Usage: %s <Ogg/Vorbis filename>\n", argv[0]);
        return -1;
    }

    /* Create gstreamer elements */
    pipeline    = gst_pipeline_new("audio-player");
    source      = gst_element_factory_make("filesrc", "file-source");
    demuxer     = gst_element_factory_make("oggdemux", "ogg-demuxer");
    decoder     = gst_element_factory_make("vorbisdec", "vorbis-decoder");
    conv        = gst_element_factory_make("audioconvert", "converter");
    sink        = gst_element_factory_make("autoaudiosink", "audio-output");

    if (!pipeline || !source || !demuxer
            || !decoder || !conv || !sink) {
        return -1;
    }

    /* set up the pipeline */


    /* set the input filename to the source element */
    g_object_set(G_OBJECT(source), "location", argv[1], NULL);

    /* add a message handler */
    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    busWatchID = gst_bus_add_watch(bus, bus_call, loop);
    gst_object_unref(bus);

    /* add all elements into pipeline */
    /* file-source | ogg-demuxer | vorbis-decoder | converter | alsa-output */
    gst_bin_add_many(GST_BIN(pipeline),
                     source, demuxer, decoder, conv, sink, NULL);

    /* link the elements together */
    /* file-source -> ogg-demuxer ~~> vorbis-decoder -> converter -> alsa-output */
    gst_element_link(source, demuxer);
    gst_element_link_many(decoder, conv, sink, NULL);

    g_signal_connect(demuxer, "pad-added", G_CALLBACK(on_pad_added), decoder);

    g_message("%s[%d] Now Playing: %s", __func__, __LINE__, argv[1]);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    /* Iterate */
    g_message("%s[%d] Running", __func__, __LINE__);
    g_main_loop_run(loop);

    /* Out of the main loop, clean up nicely */
    g_message("%s[%d]Returned, Stopping playback", __func__, __LINE__);
    gst_element_set_state(pipeline, GST_STATE_NULL);

    g_message("%s[%d]Deleting pipeline", __func__, __LINE__);
    gst_object_unref(GST_OBJECT(pipeline));
    g_source_remove(busWatchID);
    g_main_loop_unref(loop);

    return 0;
}
